package com.mikiya.plugin;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*;
import com.intellij.psi.PsiMethod;

public class ComplexityCalculator {
    private int complexity = 1;
    private static JavaParser javaParser = new JavaParser();

    public MethodDeclaration convertToMethodDeclaration(PsiMethod psiMethod) {
        String code = psiMethod.getText();
        ParseResult<MethodDeclaration> parseResult = javaParser.parseMethodDeclaration(code);
        if (parseResult.isSuccessful() && parseResult.getResult().isPresent()) {
            return parseResult.getResult().get();
        } else {
            //"Provided PsiMethod cannot be converted to MethodDeclaration."
            return null;
        }
    }

    public int calculateCyclomaticComplexity(PsiMethod psiMethod) {
        MethodDeclaration node = convertToMethodDeclaration(psiMethod);
        if (node == null) {
            return 0;
        }
        complexity = 1;
        calculateCyclomaticComplexity(node);
        return complexity;
    }

    private void calculateCyclomaticComplexity(Node node) {
        if (node == null) {
            return;
        }
        for (Node child : node.getChildNodes()) {
            if (child instanceof IfStmt || child instanceof ForStmt ||
                    child instanceof WhileStmt || child instanceof DoStmt ||
                    child instanceof SwitchStmt) {
                complexity++;
            }
            if (child instanceof BinaryExpr) {
                BinaryExpr binaryExpr = (BinaryExpr) child;
                if (BinaryExpr.Operator.OR.equals(binaryExpr) || BinaryExpr.Operator.AND.equals(binaryExpr)) {
                    complexity++;
                }
            }

            calculateCyclomaticComplexity(child);
        }
    }
}
